package jp.sourceforge.akjrcp.text_douga.audio;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import jp.sourceforge.akjrcp.ffmpeg.FFMpegPreference;
import jp.sourceforge.akjrcp.ffmpeg.InputStreamFFMpegExecuter;
import jp.sourceforge.akjrcp.text_douga.DougaSystem;

public class AudioUtils {
public static final int NOT_SPECIFIED=-1;
public static Log log=LogFactory.getLog(AudioUtils.class);
	public static InputStreamFFMpegExecuter createAudioFFMpegExecuter(String ffmpegPath,String inputFile,int rate,int channel){
		InputStreamFFMpegExecuter executer=new InputStreamFFMpegExecuter();
		FFMpegPreference preference=new FFMpegPreference();
		preference.setFfmpegPath(ffmpegPath);
		preference.setAudioRate(rate);
		preference.setAudioChannel(channel);
		
		preference.setExtension("wav");
		
		return executer;
	}
	
	public static long copyAudio(String ffmpegPath,String input,double start,double duration,OutputStream output) throws IOException{
		AudioInput audioInput=new AudioInput(ffmpegPath,input,start,duration);
		InputStream inputStream=audioInput.getInputStream();
		audioInput.startInput();
		
		long writed=0;
		int r;
		byte bytes[]=new byte[1024];
		while((r=inputStream.read(bytes))!=-1){
			if(DougaSystem.cancelling){
				log.info("dougasystem cancelled");
				break;
			}
			output.write(bytes,0,r);
			writed+=r;
		}
		inputStream.close();//done
		return writed;
	}
	
	public static long loopAudio(String ffmpegPath,String input,double start,double duration,int looptime,double padtime,boolean cutInLoop,long maxbyte,OutputStream output) throws IOException{
		if(looptime==0){
			return 0;
		}
		log.info("cutInLoop:"+cutInLoop);
		File tmp=File.createTempFile("loop", ".pcm");
		tmp.deleteOnExit();
		BufferedOutputStream bout=new BufferedOutputStream(new FileOutputStream(tmp));
		copyAudio(ffmpegPath,input,start,duration,bout);
		bout.close();
		int index=0;
		
		long writed=0;
		boolean loop=true;
		LOOP:while(loop){
		BufferedInputStream binput=new BufferedInputStream(new FileInputStream(tmp));
		byte bts[]=new byte[1024];
		int w;
		
		while((w=binput.read(bts))!=-1){
			if(DougaSystem.cancelling){
				log.info("dougasystem cancelled");
				break LOOP;
			}
				if(maxbyte>0){
					if(writed+w<maxbyte){
						output.write(bts,0,w);
						writed+=w;
					}else{//over limit
						int r=(int) (maxbyte-writed);
						
						if(cutInLoop){
							output.write(bts,0,r);
							writed+=r;
							binput.close();
							//log.info("break loop");
							break LOOP;
						}else{
							output.write(bts,0,w);
							writed+=w;
							//log.info("loop false");
							loop=false;
						}
					}
				}else{
					output.write(bts,0,w);
					writed+=w;
				}
			}
		binput.close();
		index++;
		if(index==looptime){
			loop=false;
			}
		
		if(loop){//has next
			if(padtime>0){
				writed+=writeZero(output,padtime,48000,2);//TODO
				}
			}
		}
		
	
		return writed;
	}
	public static long writeZero(OutputStream output,double time,int rate,int channel) throws IOException{
		
		long mustread=new BigDecimal(""+time).multiply(new BigDecimal(rate*channel*2)).longValue();
//		fill space 
		byte bts[]=new byte[1024];
		long writed=0;
		while(writed<mustread){
			int w;
			if(writed+bts.length<mustread){
				w=bts.length;
			}else{
				w=(int)(mustread-writed);
			}
			output.write(bts,0,w);
			writed+=w;
		}
		log.info("zero:"+writed);
		return writed;
	}
	//s16 48 2ch
	public static void s16leToWav(File input,File output) throws IOException{
		long frames=input.length()/4;
		AudioFormat format=new AudioFormat(48000,16,2,true,false);
		log.info("frames:"+frames);
		AudioInputStream ainput=new AudioInputStream(new BufferedInputStream(new FileInputStream(input)),format,frames);

		
			OutputStream fout = new BufferedOutputStream(new FileOutputStream(output));
			long writtenBytes=AudioSystem.write(
			        ainput
			        ,AudioFileFormat.Type.WAVE,
			       fout);
			log.info("writed:"+writtenBytes);
			fout.close();
		
	}

}
